package com.pentofab.payrollmanagement.utilities;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;

import com.pentofab.payrollmanagement.application.PayrollApplicationFactory;
import com.pentofab.payrollmanagement.dao.AttendanceDao;
import com.pentofab.payrollmanagement.dao.model.Attendance;
import com.pentofab.payrollmanagement.dao.model.Employee;
import com.pentofab.payrollmanagement.database.impl.EmployeeTableSQLConstants;
import com.pentofab.payrollmanagement.exception.BusinessException;
import com.pentofab.payrollmanagement.exception.ExceptionMsg;

public class PayRollUtility implements Constants, ExceptionMsg {

	public static void debug(String message) {

		System.out.println(message);
			try {

				String date = convertDateToString(new Date());
				File logDir = new File("E:\\LOGS_DONT_DELETE\\");
				if (!logDir.exists()) {
					logDir.mkdir();
				}
				File logFileName = new File("E:\\LOGS_DONT_DELETE\\" + date + ".txt");
				if (!logFileName.exists()) {
					logFileName.createNewFile();
				}
				FileWriter frw = new FileWriter(logFileName, true);
				frw.write(message);
				frw.write("\n");
				frw.close();
			} catch (Exception e) {
				e.printStackTrace();
				System.out.println("Exception while handling logs");
			}


	}

	/**
	 * Validate emp id.
	 * 
	 * @param empId
	 *            the emp id
	 * @return true, if successful
	 * @throws BusinessException
	 *             the business exception
	 */
	public static boolean validateEmpId(String empId) throws BusinessException {

		if (empId == null || empId.trim().equals("")) {
			throw new BusinessException(NULL_EMPTY_ID);
		}
		if (!empId.matches("[A-Za-z]{2}[0-9]{4,6}")) {
			throw new BusinessException(INVALID_EMPLOYEE_ID + empId);
		}
		return true;
	}

	/**
	 * Validate emp name.
	 * 
	 * @param empName
	 *            the emp name
	 * @return true, if successful
	 * @throws BusinessException
	 *             the business exception
	 */
	public static boolean validateEmpName(String empName)
			throws BusinessException {

		PayRollUtility.debug("empName : " + empName);
		if (empName == null || empName.trim().equals("")) {
			throw new BusinessException(NULL_EMPTY_NAME);
		}
		if (empName.trim().length() < 3) {
			throw new BusinessException(INVALID_KEY_TO_SERCH);
		}
		return true;
	}

	/**
	 * Convert date to string.
	 * 
	 * @param date
	 *            the date
	 * @return the string
	 * @throws BusinessException
	 *             the business exception
	 */
	public static String convertDateToString(Date date)
			throws BusinessException {

		if (date != null) {
			SimpleDateFormat dateFormat = new SimpleDateFormat(Constants.dateFormat);
			return dateFormat.format(date);
		}
		throw new BusinessException("DATE" + MANDATORY_ATTRIBUTE_IS_NULL);

	}
	
	public static Date convertStringToDate(String date)
			throws BusinessException {
		try{
			SimpleDateFormat dateFormat = new SimpleDateFormat(Constants.dateFormat);
			return dateFormat.parse(date);
		}catch(Exception we){
			throw new BusinessException("Invalid date. Please select proper date : "+date);
		}
	}

	/**
	 * Validate time.
	 * 
	 * @param time
	 *            the time
	 * @return true, if successful
	 */
	public static boolean validateTime(String time) {

		if (time.trim().equals("")) {
			return true;
		}
		if (!time.contains(":")) {
			return false;
		}
		String[] timeArray = time.split(":");
		int hour = validateNumber(timeArray[0]);
		int minute = validateNumber(timeArray[1]);
		if (hour < 0 || hour > 23) {
			return false;
		}
		if (minute < 0 || minute >= 60) {
			return false;
		}
		return true;
	}

	/**
	 * Validate number.
	 * 
	 * @param number
	 *            the number
	 * @return the int
	 */
	public static int validateNumber(String number) {
		try {
			int numberInt = Integer.valueOf(number);
			return numberInt;
		} catch (NumberFormatException e) {
			return -1;
		}
	}

	public static void validateComments(String comments)
			throws BusinessException {
		if (comments == null || comments.trim().equals("")) {
			throw new BusinessException(COMMENTS_CANT_BE_EMPTY);
		}
		if (comments.trim().length() < 30) {
			throw new BusinessException(COMMENTS_LENGTH_NOT_VALID);
		}
	}

	/**
	 * Validate attandance.
	 * 
	 * @param attandance
	 *            the attandance
	 * @throws BusinessException
	 */
	public static void validateAttandance(Attendance attandance)
			throws BusinessException {

		if (attandance == null) {
			throw new BusinessException(ATTANDANCE_OBJECT_CANT_BE_NULL);
		}
		if (attandance.getLogoutTime().equals(attandance.getLoginTime())) {
			throw new BusinessException(BOTH_TIME_SAME);
		}
		validateLoginTime(attandance.getLoginTime());
		validateLogOutTime(attandance.getLogoutTime());
		if (compareDateWithToday(attandance.getDate()) == 0) {
			compareInOutTime(attandance.getLoginTime(), attandance
					.getLogoutTime());
		} else if (compareDateWithToday(attandance.getDate()) > 0) {
			throw new BusinessException(ERROR_WHILE_ADDING_ATTANDANCE_INFO);
		}
	}

	public static void validateLoginTime(String loginTime)
			throws BusinessException {
		if (!PayRollUtility.validateTime(loginTime)) {
			throw new BusinessException(INVALI_LOGIN_TIME + loginTime);
		}
	}

	public static void validateLogOutTime(String logOutTime)
			throws BusinessException {
		if (!PayRollUtility.validateTime(logOutTime)) {
			throw new BusinessException(INVALID_LOGOUT_TIME + logOutTime);
		}
	}

	public static void compareInOutTime(String loginTme, String logOutTime)
			throws BusinessException {

		if (loginTme.equals("") && !logOutTime.equals("")) {
			throw new BusinessException(INVALI_LOGIN_TIME);
		} else if (logOutTime.equals("")) {
			return;
		}
		String[] loginTmeDetails = loginTme.split(":");
		String[] logOutTmeDetails = logOutTime.split(":");
		int loginHrs = Integer.parseInt(loginTmeDetails[0]);
		int loginMins = Integer.parseInt(loginTmeDetails[1]);
		int logOutHrs = Integer.parseInt(logOutTmeDetails[0]);
		int logOutMins = Integer.parseInt(logOutTmeDetails[1]);
		
		Calendar inTime =Calendar.getInstance();
		inTime.set(Calendar.HOUR_OF_DAY,loginHrs);
		inTime.set(Calendar.MINUTE,loginMins);
		inTime.set(Calendar.SECOND,0);
		
		Calendar outTime = (Calendar)inTime.clone();
		outTime.set(Calendar.HOUR_OF_DAY,logOutHrs);
		outTime.set(Calendar.MINUTE,logOutMins);
		
		if (inTime.compareTo(outTime) > 0) {
			throw new BusinessException(LOGOUT_OUT_TIME_LESS_THAN_LOGIN_TIME
					+ "Login time :" + loginTme + ". Log out timne : "
					+ logOutTime);
		} 
	}

	public static void validateRowNum(int rowNumber) throws BusinessException {
		if (rowNumber <= 0) {
			throw new BusinessException(INVALI_ROW_NUMBER + rowNumber);
		}
	}

	public static void validateEmployee(Employee employee)
			throws BusinessException {

		validateEmpId(employee.getEmpId());
	}

	public static ArrayList<String> getAllEmpName(
			ArrayList<Employee> allEmployeeInfo) {

		System.out.println("allEmployeeInfo : " + allEmployeeInfo);
		ArrayList<String> empNameList = new ArrayList<String>();
		Iterator<Employee> empNameIterator = allEmployeeInfo.listIterator();
		while (empNameIterator.hasNext()) {
			empNameList.add(empNameIterator.next().getEmpName());
		}
		PayRollUtility.debug("empNameList : " + empNameList);
		return empNameList;
	}

	public static int compareDateWithToday(String date)
			throws BusinessException {

		debug("compare " + date + " With Today :" + new Date());
		try {
			SimpleDateFormat format = new SimpleDateFormat(Constants.dateFormat);
			Date dateFromAtt = format.parse(date);
			return dateFromAtt.compareTo(new Date());

		} catch (ParseException e) {
			e.printStackTrace();
			throw new BusinessException(
					"Error during Date Comparision in compareDateWithToday");
		}
	}
	
	public static boolean isPreviousMonth(String date)
			throws BusinessException {

		debug("Checking to is if given date is previous month "+date);
		try {
			SimpleDateFormat format = new SimpleDateFormat(Constants.dateFormat);
			format.parse(date);
			Calendar givenDateCal = format.getCalendar();
			Calendar currentDate = Calendar.getInstance();
			
			return(givenDateCal.get(2) < currentDate.get(2) && 
					givenDateCal.get(1) < currentDate.get(1));
			
		} catch (ParseException e) {
			e.printStackTrace();
			throw new BusinessException(
					"Error during isPreviousMonth checking");
		}
	}
	
	public static boolean isValidDate(String date) {
		Pattern pattern = Pattern
				.compile("(0?[1-9]|[12][0-9]|3[01])/(0?[1-9]|1[012])/((19|20|21)\\d\\d)");
		Matcher matcher = pattern.matcher(date);
		return matcher.matches();
	}


	public static int getMaxDayofMonth(int year, int month) {

		debug("year : " + year);
		debug("month : " + month);
		Calendar calendar = Calendar.getInstance();
		calendar.set(Calendar.MONTH, month);
		calendar.set(year, month, 1);
		return calendar.getActualMaximum(Calendar.DAY_OF_MONTH);

	}

	public static int getYear() {

		Calendar calendar = Calendar.getInstance();
		return calendar.get(Calendar.YEAR);

	}
	/*
	 * Return < 0 of first date before second returns = if both dates are same
	 * returns > 0 if first date after second date
	 */
	public static int compareTwoDates(String date1, String date2)
			{

		debug("date1 " + date1 + " With date2 :" + date2);
		try {
			SimpleDateFormat format = new SimpleDateFormat(Constants.dateFormat);
			Date dateOne = format.parse(date1);
			Date dateTwo = format.parse(date2);

			return dateOne.compareTo(dateTwo);
		} catch (ParseException e) {
			
			debug("Error durin comparing two dates date1  "+date1+" - date2"+date2);
		}
		return 999;
	}

	public static int noOfDaysBetweenTwoDates(String date1, String date2)
			 {
		
		debug("date1 " + date1 + " With date2 :" + date2);
		try {
			SimpleDateFormat format = new SimpleDateFormat(Constants.dateFormat);
			Date dateOne = format.parse(date1);
			Date dateTwo = format.parse(date2);
			int numberOfDays = 1;
			while(dateOne.before(dateTwo)){
				dateOne.setDate(dateOne.getDate()+1);
				numberOfDays++;
			}
			return numberOfDays;

		} catch (Exception e) {
			debug("Error durin noOfDaysBetweenTwoDates two dates date1  "+date1+" - date2"+date2);
		}
		return -1;
	}
	
	
	public static void encrypt(String key, String inputFile, String outPutFile) throws Throwable {
		
		FileInputStream is = new FileInputStream(inputFile);
		FileOutputStream os = new FileOutputStream(outPutFile);
		
		 DESKeySpec dks = new DESKeySpec(key.getBytes());
		    SecretKeyFactory skf = SecretKeyFactory.getInstance("DES");
		    SecretKey desKey = skf.generateSecret(dks);
		    Cipher cipher = Cipher.getInstance("DES");
		    
		    cipher.init(Cipher.ENCRYPT_MODE, desKey);
	        CipherInputStream cis = new CipherInputStream(is, cipher);
	        doCopy(cis, os);
	}

	public static void decrypt(String key, String inputFile, String outputFile) throws Throwable {
	    
		FileInputStream is = new FileInputStream(inputFile);
		FileOutputStream os = new FileOutputStream(outputFile);
		 DESKeySpec dks = new DESKeySpec(key.getBytes());
		    SecretKeyFactory skf = SecretKeyFactory.getInstance("DES");
		    SecretKey desKey = skf.generateSecret(dks);
		    Cipher cipher = Cipher.getInstance("DES");
		    
		    cipher.init(Cipher.DECRYPT_MODE, desKey);
	        CipherOutputStream cos = new CipherOutputStream(os, cipher);
	        doCopy(is, cos);
	}


	public static void doCopy(InputStream is, OutputStream os) throws IOException {
		
	    byte[] bytes = new byte[64];
	    int numBytes;
	    while ((numBytes = is.read(bytes)) != -1) {
	        os.write(bytes, 0, numBytes);
	    }
	    os.flush();
	    os.close();
	    is.close();
	}
	
	public static int dayOfWeek(String dayOfWeek) {
		
		Hashtable<String, Integer> dayOfWeekInfoMap = new Hashtable<String, Integer>();
		
		dayOfWeekInfoMap.put("Sunday", 1);
		dayOfWeekInfoMap.put("Monday", 2);
		dayOfWeekInfoMap.put("Tuesday", 3);
		dayOfWeekInfoMap.put("Wednesday",4);
		dayOfWeekInfoMap.put("Thursday", 5);
		dayOfWeekInfoMap.put("Friday", 6);
		dayOfWeekInfoMap.put("Saturday", 7);

		return dayOfWeekInfoMap.get(dayOfWeek);
	}

	public static ArrayList<HashMap<String, String>> getEmployeeList(File destinationFile) {

		
		System.out.println("destinationFile ;"+destinationFile);
		 ArrayList<HashMap<String, String>> empInfoMapList = null;
		try {
			if (destinationFile == null)
				return null;

			BufferedReader br = new BufferedReader(new FileReader(destinationFile));
			String[] hearedArray = null;
			boolean firstLine =true;
			String currentLine = null;
			
			  empInfoMapList = new ArrayList<HashMap<String,String>>();
			
			while((currentLine = br.readLine()) != null){
				System.out.println("currentLine : "+currentLine);
				currentLine = currentLine.replace("'", "");
				String[] dataArray = null;
				if(firstLine){
					hearedArray = currentLine.split(",");
					firstLine = false;
				}else{
					dataArray =  currentLine.split(",");
					HashMap<String, String> dataMap = new HashMap<String, String>();
					
					if(dataArray.length != hearedArray.length){
						throw new BusinessException("Inconsistent data in the file. Please check data in file for correctness.");
					}
					
					for(int i=0 ;i<dataArray.length;i++){
						
						dataMap.put(EmployeeTableSQLConstants.Table_Employee.tableName+"."+hearedArray[i].trim(), dataArray[i].trim());
					}
					System.out.println("dataMap : "+dataMap);
					empInfoMapList.add(dataMap);
				}
			}
			
		} catch (Exception e) {
			e.printStackTrace();
		}
		System.out.println("empInfoMapList : "+empInfoMapList);
		return empInfoMapList;
	}

	public static String decilamFormat(String decimal) {
		try {
			String dcimal ="";
			DecimalFormat df = new DecimalFormat("#.##");
			dcimal = df.format(Double.parseDouble(decimal));
			
//			double count = Double.parseDouble(dcimal);
			
//			if(decimal.)
//			Math.ceil(count);
			return dcimal;
		} catch (Exception e) {
			return decimal;
		}
	}
	
	/*public static void main(String[] args) {
		
		AttendanceDao d = PayrollApplicationFactory.getAttandanceMgmt();
		for (int i = 1; i <= 30; i++) {
			String date = i+"-09-2013";
		try {
			d.addAttandeanceEntry("NC1000", PayRollUtility.convertStringToDate(date), "10:00", "20:00", "Santhosh", 1, true, true);
		} catch (BusinessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		}
	}*/
	
	
	public static String addTime(String time1, String time2){
	
		String[] time = time1.split(":");
		int hrs = Integer.parseInt(time[0]);
		int mins = Integer.parseInt(time[1]);
		
		String[] OutTime = time2.split(":");
		int outHrs = Integer.parseInt(OutTime[0]);
		int outMins = Integer.parseInt(OutTime[1]);
		
		int totalHrs = hrs+outHrs;
		int totalMins = mins+outMins;
		
		if(totalMins > 60){
			totalHrs = totalHrs+1;
			totalMins = totalMins -60;
		}
		return totalHrs+":"+totalMins;
	}
	
	public static String subTractTime(String in, String out){
		
		String[] time = in.split(":");
		int hrs = Integer.parseInt(time[0]);
		int mins = Integer.parseInt(time[1]);
		
		String[] OutTime = out.split(":");
		int outHrs = Integer.parseInt(OutTime[0]);
		int outMins = Integer.parseInt(OutTime[1]);
		
		int inMins = (hrs*60)+mins;
		int totalOutMins = (outHrs*60)+outMins;
		
		if(totalOutMins < inMins){
			totalOutMins = totalOutMins + (24*60);
		}
		
	int totalTime  = totalOutMins - inMins;
	
	int actualHrs = totalTime/60;
	int acutalMins = totalTime -  (actualHrs*60);
		
		return actualHrs+":"+acutalMins;
	}
	
	public static LinkedHashSet<String> getDatesForMonth(int maxdays, String firstDay) throws Exception{
		
		
		SimpleDateFormat smt = new SimpleDateFormat(Constants.dateFormat);
		smt.parse(firstDay);
		
		LinkedHashSet<String> emptyMap =new LinkedHashSet<String>();
		
		SimpleDateFormat sm = new SimpleDateFormat(PayRollUtility.dateFormat);
		sm.setCalendar(smt.getCalendar());
		Calendar cal = sm.getCalendar();
		emptyMap.add(sm.format(cal.getTime()));
		for (int i = 1; i < maxdays; i++) {
			cal.add(Calendar.DATE, 1);
			emptyMap.add(sm.format(cal.getTime()));
		}
		
		return emptyMap;
	}
	
	public static String getNextOrPrevDate(String date, boolean next, boolean prev) throws Exception{
		SimpleDateFormat smDateFormat = new SimpleDateFormat(Constants.dateFormat);
		smDateFormat.parse(date);
		Calendar cal = smDateFormat.getCalendar();
		
		if(next){
			
			cal.add(Calendar.DATE, 1);
		}
		if(prev){
			
			cal.add(Calendar.DATE, -1);
		}
		return convertDateToString(cal.getTime());
	}
	
}
